/*
 * Copyright (C) 2008 by The Regents of the University of California
 * Redistribution of this file is permitted under the terms of the GNU
 * Public License (GPL).
 *
 * @author Junghoo "John" Cho <cho AT cs.ucla.edu>
 * @date 3/24/2008
 */
 
#include "BTreeIndex.h"
#include "BTreeNode.h"

using namespace std;

/*
 * BTreeIndex constructor
 */
BTreeIndex::BTreeIndex()
{
    rootPid = -1;
	treeHeight = 0;
}

// Open the index file in read or write mode.
// Under 'w' mode, the index file should be created if it does not exist.
RC BTreeIndex::open(const string& indexname, char mode) {
	int retval = pf.open(indexname, mode);

	// Read values from pagefile
	if (retval == 0) {
		char buf[1024];
		char rp[4];
		char th[4];
		pf.read(0, buf);
		memcpy(rp, buf, 4);
		rootPid = (int) (rp);
		memcpy(th, buf+4, 4);
		treeHeight = (int) (th);
	}

    return retval;
}

// Close the index file.
RC BTreeIndex::close() {
	// Write values to pagefile
	char buf[1024];
	char rp[4];
	rp[0] = (char) rootPid;
	char th[4];
	th[0] = (char) treeHeight;
	memcpy(buf, rp, 4);
	memcpy(buf+4, th, 4);
	pf.write(0, buf);

	int retval = pf.close();
    return retval;
}

// Insert (key, RecordId) pair to the index.
RC BTreeIndex::insert(int key, const RecordId& rid) {
	int depth = 1; // Depth of current node
	PageId pid;

	if (treeHeight == 0) {	// Empty tree
		BTLeafNode leaf;		// Create root/leaf node
		leaf.insert(key, rid);	// Insert (key, RecordID) pair to node

		rootPid = pf.endPid();	// Set new rootPid
		treeHeight = 1;			// and treeHeight

		int retval = leaf.write(rootPid, pf);
		return retval;
	}
	else
		pid = rootPid;
	while (depth <= treeHeight) {
		if (depth == treeHeight) {	// Leaf node
			BTLeafNode leaf;
			leaf.read(pid, pf);
			if (leaf.insert(key, rid) == 0)		// Leaf has space
				leaf.write(pid, pf);	// Insert to leaf
			else {								// Leaf is full
				BTLeafNode nextleaf;	// Create sibling node
				int nextkey;			// and key
				leaf.insertAndSplit(key, rid, nextleaf, nextkey);
				leaf.setNextNodePtr(pf.endPid());	// Point to next leaf

				// Write nodes
				leaf.write(pid, pf);
				nextleaf.write(pf.endPid(), pf);
			}
			return 0;
		}
		else {						// Non-leaf node
			// TODO: implement non-leaf node portion
		}
	}

    return 0;
}

// Find the leaf-node index entry whose key value is larger than or 
// equal to searchKey, and output the location of the entry in IndexCursor.
// IndexCursor is a "pointer" to a B+tree leaf-node entry consisting of
// the PageId of the node and the SlotID of the index entry.
// Once the location of the index entry is identified and returned 
// from this function, you should call readForward() to retrieve the
// actual (key, rid) pair from the index.
RC BTreeIndex::locate(int searchKey, IndexCursor& cursor) {
	PageId	pid = rootPid;
	int		eid;

	BTNonLeafNode	node;
	BTLeafNode		leaf;

	int nodeDepth = 1;

	// Follow path to correct leaf node
	while (nodeDepth <= treeHeight) {
		node.read(pid, pf);						// Read current node
		node.locateChildPtr(searchKey, pid);	// Get pid of next node
		nodeDepth++;
	}

	cursor.pid = pid;				// Found leaf node, set cursor's PageID

	leaf.read(pid, pf);				// Read leaf node
	leaf.locate(searchKey, eid);	// Get eid of leaf node
	cursor.eid = eid;				// Found entry, set cursor's EntryID

    return 0;
}

// Read the (key, rid) pair at the location specified by the index cursor,
// and move foward the cursor to the next entry.
RC BTreeIndex::readForward(IndexCursor& cursor, int& key, RecordId& rid) {
	BTLeafNode leaf;

	leaf.read(cursor.pid, pf);				// Read leaf node
	leaf.readEntry(cursor.eid, key, rid);	// Read entry
	cursor.eid++;							// Move to next entry

    return 0;
}
